package com.wwu.common.redis;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.wwu.common.constant.CommConst;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * Redis缓存及连接池配置
 * 需要在启动类中使用@EnableCaching注解开启缓存
 * @author 一蓑烟雨
 * @date 2021-11-15 11:14
 * @version 1.0.0
 **/
@Configuration
public class RedisConfig extends CachingConfigurerSupport {

    /**
     * redisTemplate模板配置，提供缓存操作对象
     * @param connectionFactory
     * @return org.springframework.data.redis.core.RedisTemplate<java.lang.String,java.lang.Object>
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 下午 19:44
     */
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        //配置连接工厂
        redisTemplate.setConnectionFactory(connectionFactory);
        //String类型key序列化
        redisTemplate.setKeySerializer(keySerializer());
        //String类型value序列化
        redisTemplate.setValueSerializer(valueSerializer());
        //Hash类型Key序列化
        redisTemplate.setHashKeySerializer(keySerializer());
        //Hash类型Value序列化
        redisTemplate.setHashValueSerializer(valueSerializer());
        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }

    /**
     * redis缓存key键序列化,也可以用于String类型的值序列化
     *
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 上午 11:48
     */
    private RedisSerializer<String> keySerializer() {
        return new StringRedisSerializer();
    }

    /**
     * redis缓存value值序列化
     * 其默认的序列化方式为JdkSerializationRedisSerializer，这种方式跨语言和可读性都不太好
     * Jackson2JsonRedisSerializer序列化结果清晰、容易阅读、存储量少、速度快
     * @author 一蓑烟雨
     * @date 2021/11/15 0015 上午 11:50
     */
    private RedisSerializer<Object> valueSerializer() {
        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
        Jackson2JsonRedisSerializer jacksonSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        //处理不同时区的时间偏差
        om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        //日期类型字段序列化和反序列处理
        om.registerModule(new JavaTimeModule()
                //序列化
                .addSerializer(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern(CommConst.DATE)))
                .addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(CommConst.DATE_TIME)))
                //反序列化
                .addDeserializer(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern(CommConst.DATE)))
                .addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(CommConst.DATE_TIME)))

        );

        jacksonSerializer.setObjectMapper(om);
        return jacksonSerializer;
    }
}
